package main

import (
	"encoding/json"
	"fmt"
	"reflect"
	"time"
)

// ==========================================
// 基本结构体定义
// ==========================================

// Person3 结构体
type Person1 struct {
	Name    string
	Age     int
	Gender  string
	Address string
}

// 带标签的结构体
type User struct {
	ID        int       `json:"id" validate:"required"`
	Username  string    `json:"username" validate:"required,min=4,max=20"`
	Email     string    `json:"email" validate:"required,email"`
	CreatedAt time.Time `json:"created_at"`
}

// ==========================================
// 嵌套结构体
// ==========================================

// Address 结构体
type Address struct {
	Street  string
	City    string
	State   string
	ZipCode string
}

// Employee 结构体（包含嵌套结构体）
type Employee struct {
	ID      int
	Name    string
	Address Address     // 常规嵌套
	Contact ContactInfo // 常规嵌套
}

// ContactInfo 结构体
type ContactInfo struct {
	Email  string
	Phone  string
	WeChat string
}

// ==========================================
// 结构体嵌入（继承）
// ==========================================

// Animal1 基础结构体
type Animal1 struct {
	Name  string
	Age   int
	Sound string
}

// Dog1 结构体（嵌入Animal）
type Dog1 struct {
	Animal1 // 嵌入Animal结构体
	Breed   string
}

// Cat 结构体（嵌入Animal）
type Cat struct {
	Animal1       // 嵌入Animal结构体
	ClimbingSkill int
}

// ==========================================
// 结构体方法
// ==========================================

// Person的方法（值接收者）
func (p Person1) Introduce() string {
	return fmt.Sprintf("我是%s，今年%d岁，性别%s，住在%s", p.Name, p.Age, p.Gender, p.Address)
}

// Person的方法（指针接收者）
func (p *Person1) Birthday() {
	p.Age++
}

// Animal的方法
func (a Animal1) MakeSound() string {
	return fmt.Sprintf("%s说：%s", a.Name, a.Sound)
}

// Dog的方法
func (d Dog1) Fetch() string {
	return fmt.Sprintf("%s去捡球了", d.Name)
}

// Cat的方法
func (c Cat) Climb() string {
	return fmt.Sprintf("%s正在爬树，技能等级：%d", c.Name, c.ClimbingSkill)
}

func main() {
	// ==========================================
	// 结构体的创建和初始化
	// ==========================================

	// 方法1：使用var声明
	var person1 Person1
	person1.Name = "张三"
	person1.Age = 25
	person1.Gender = "男"
	person1.Address = "北京市"

	// 方法2：使用字面量
	person2 := Person1{
		Name:    "李四",
		Age:     30,
		Gender:  "女",
		Address: "上海市",
	}

	// 方法3：使用new函数（返回指针）
	person3 := new(Person1)
	person3.Name = "王五" // 自动解引用
	person3.Age = 35
	person3.Gender = "男"
	person3.Address = "广州市"

	// 打印结构体
	fmt.Printf("person1: %+v\n", person1)
	fmt.Printf("person2: %+v\n", person2)
	fmt.Printf("person3: %+v\n", person3)

	// ==========================================
	// 结构体方法的使用
	// ==========================================

	// 调用值接收者方法
	fmt.Println(person1.Introduce())

	// 调用指针接收者方法
	person1.Birthday()
	fmt.Printf("过生日后：%s现在%d岁了\n", person1.Name, person1.Age)

	// ==========================================
	// 嵌套结构体的使用
	// ==========================================

	// 创建员工
	employee := Employee{
		ID:   1001,
		Name: "赵六",
		Address: Address{
			Street:  "人民路",
			City:    "深圳市",
			State:   "广东省",
			ZipCode: "518000",
		},
		Contact: ContactInfo{
			Email:  "zhaoliu@example.com",
			Phone:  "13800138000",
			WeChat: "zhaoliu123",
		},
	}

	// 访问嵌套字段
	fmt.Printf("\n员工信息：\n")
	fmt.Printf("姓名：%s\n", employee.Name)
	fmt.Printf("地址：%s %s %s\n", employee.Address.State, employee.Address.City, employee.Address.Street)
	fmt.Printf("联系方式：电话-%s，邮箱-%s\n", employee.Contact.Phone, employee.Contact.Email)

	// ==========================================
	// 结构体嵌入（继承）的使用
	// ==========================================

	// 创建狗
	dog := Dog1{
		Animal1: Animal1{
			Name:  "旺财",
			Age:   3,
			Sound: "汪汪汪",
		},
		Breed: "金毛",
	}

	// 创建猫
	cat := Cat{
		Animal1: Animal1{
			Name:  "咪咪",
			Age:   2,
			Sound: "喵喵喵",
		},
		ClimbingSkill: 8,
	}

	// 调用继承的方法和自己的方法
	fmt.Printf("\n动物叫声：\n")
	fmt.Println(dog.MakeSound()) // 继承自Animal的方法
	fmt.Println(dog.Fetch())     // Dog自己的方法
	fmt.Println(cat.MakeSound()) // 继承自Animal的方法
	fmt.Println(cat.Climb())     // Cat自己的方法

	// ==========================================
	// 结构体标签的使用
	// ==========================================

	// 创建用户
	user := User{
		ID:        1,
		Username:  "admin",
		Email:     "admin@example.com",
		CreatedAt: time.Now(),
	}

	// 将结构体转换为JSON
	jsonData, _ := json.MarshalIndent(user, "", "    ")
	fmt.Printf("\n结构体转JSON：\n%s\n", string(jsonData))

	// 获取结构体标签
	t := reflect.TypeOf(user)
	fmt.Printf("\n结构体标签：\n")
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		fmt.Printf("%s: %s\n", field.Name, field.Tag)
	}

	// ==========================================
	// 结构体的比较
	// ==========================================

	p1 := Person1{Name: "张三", Age: 25, Gender: "男", Address: "北京"}
	p2 := Person1{Name: "张三", Age: 25, Gender: "男", Address: "北京"}
	p3 := Person1{Name: "李四", Age: 30, Gender: "女", Address: "上海"}

	// 直接比较
	fmt.Printf("\n结构体比较：\n")
	fmt.Printf("p1 == p2: %v\n", p1 == p2)
	fmt.Printf("p1 == p3: %v\n", p1 == p3)

	// ==========================================
	// 结构体作为map的键
	// ==========================================

	// 注意：只有所有字段都是可比较的结构体才能用作map的键
	type Point struct {
		X, Y int
	}

	points := make(map[Point]string)
	points[Point{1, 2}] = "点1"
	points[Point{3, 4}] = "点2"

	fmt.Printf("\n使用结构体作为map键：\n")
	for point, name := range points {
		fmt.Printf("坐标(%d, %d): %s\n", point.X, point.Y, name)
	}

	// ==========================================
	// 练习
	// ==========================================

	// 1. 创建一个表示银行账户的结构体，包含账号、余额等字段，
	//    并实现存款和取款方法

	// 2. 创建一个图书结构体，包含标题、作者、价格等字段，
	//    并实现一个打折方法

	// 3. 创建一个学生结构体，嵌套一个成绩结构体，
	//    并实现计算平均分的方法

	// 4. 实现一个简单的员工管理系统，使用结构体表示员工，
	//    包含基本信息和工资计算方法

	// 5. 创建一个带有JSON标签的商品结构体，
	//    实现JSON序列化和反序列化
}

// ==========================================
// 练习参考实现
// ==========================================

// 1. 银行账户
type BankAccount struct {
	AccountNumber string
	Balance       float64
	Owner         string
}

func (a *BankAccount) Deposit(amount float64) error {
	if amount <= 0 {
		return fmt.Errorf("存款金额必须大于0")
	}
	a.Balance += amount
	return nil
}

func (a *BankAccount) Withdraw(amount float64) error {
	if amount <= 0 {
		return fmt.Errorf("取款金额必须大于0")
	}
	if amount > a.Balance {
		return fmt.Errorf("余额不足")
	}
	a.Balance -= amount
	return nil
}

// 2. 图书
type Book struct {
	Title  string
	Author string
	Price  float64
}

func (b *Book) ApplyDiscount(percentage float64) {
	if percentage > 0 && percentage <= 100 {
		discount := b.Price * percentage / 100
		b.Price -= discount
	}
}

// 3. 学生和成绩
type Grades struct {
	Math    float64
	English float64
	Science float64
}

type Student struct {
	Name   string
	ID     string
	Grades Grades
}

func (s Student) CalculateAverage() float64 {
	return (s.Grades.Math + s.Grades.English + s.Grades.Science) / 3
}

// 4. 员工管理
type Employee2 struct {
	ID       int
	Name     string
	Position string
	BasePay  float64
	Overtime float64
	Benefits float64
}

func (e Employee2) CalculateSalary() float64 {
	return e.BasePay + (e.Overtime * 1.5) + e.Benefits
}

// 5. 商品
type Product struct {
	ID          int     `json:"id"`
	Name        string  `json:"name"`
	Price       float64 `json:"price"`
	Description string  `json:"description,omitempty"`
	InStock     bool    `json:"in_stock"`
}
